package com.hb.B_面向对象.拓展函数

/**
 * Kotlin 同 C# 和 Gosu 类似，能够扩展一个类的新功能而无需继承该类或使用像装饰者这样的
 * 任何类型的设计模式。 这通过叫做扩展的特殊声明完成。Kotlin 支持扩展函数 和 扩展属性。
 */

fun main() {
    val list = mutableListOf(1, 2, 3)
    list.swap(0, 2) // “swap()”内部的“this”得到“l”的值
    list.forEach(::println)//3 2 1

    /**
     * 这个例子会输出 "c"，因为调用的扩展函数只取决于 参数 c 的声明类型，该类型是 C 类。
     * 如果一个类定义有一个成员函数和一个扩展函数，而这两个函数又有相同的接收者类型、相同的名字 并且都适用给定的参数，这种情况总是取成员函数。
     */
    printFoo(D())//c

    println(E().foo())//member

    //就像伴生对象的其他普通成员，只需用类名作为限定符去调用他们
    MyClass.foo()
}

/**
 *声明一个扩展函数，我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。
 * 下面 代码为 MutableList<Int> 添加一个 swap 函数:
 *
 * 这个 this 关键字在扩展函数内部对应到接收者对象(传过来的在点符号前的对象) 现在，
 * 我们对任意 MutableList<Int> 调用该函数了:
 */
fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // “this”对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}


/**
 *当然，这个函数对任何 MutableList<T> 起作用，我们可以泛化它:
 * 为了在接收者类型表达式中使用泛型，我们要在函数名前声明泛型参数。
 */
fun <T> MutableList<T>.swap2(index1: Int, index2: Int) {
    val tmp = this[index1] // “this”对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}


/**
 * 扩展是静态解析的,扩展不能真正的修改他们所扩展的类。通过定义一个扩展，
 * 你并没有在一个类中插入新成员， 仅仅是可以通过该类型的变量用点表达式去调用这个新函数。
 * 我们想强调的是扩展函数是静态分发的，即他们不是根据接收者类型的虚方法。
 * 这意味着调 用的扩展函数是由函数调用所在的表达式的类型来决定的，而不是由表达式运行时求值结果决定的
 *
 */
open class C
class D : C()

fun C.foo() = "c"
fun D.foo() = "d"
fun printFoo(c: C) {
    println(c.foo())
}

class E {
    fun foo() { println("member") }
}
fun E.foo() { println("extension") }

//可空接收者
/**
* 注意可以为可空的接收者类型定义扩展。这样的扩展可以在对象变量上调用， 即使其值为 null，
 * 并且可以在函数体内检测 this == null ，这能让你 在没有检测 null 的时候调用 Kotlin 中的toString():检测发生在扩展函数的内部。
**/
fun Any?.toString(): String {
    if (this == null) return "null"
// 空检测之后，“this”会自动转换为非空类型，所以下面的 toString() // 解析为 Any 类的成员函数
    return toString()
}

//拓展属性
/**
* 和函数类似，Kotlin 支持扩展属性:
 * 注意:由于扩展没有实际的将成员插入类中，因此对扩展属性来说 幕后字段是无效的。
 * 这就 是为什么扩展属性不能有 初始化器。他们的行为只能由显式提供的 getters/setters 定义。
* */
val <T> List<T>.lastIndex: Int
get() = size - 1

//伴生对象的扩展
/**
* 如果一个类定义有一个伴生对象 ，你也可以为伴生对象定义 扩展函数和属性:
 * 就像伴生对象的其他普通成员，只需用类名作为限定符去调用他们
* */

class MyClass {
    companion object { } // 将被称为 "Companion"
}
fun MyClass.Companion.foo() { // ......
    println("Companion.foo()")
}
/**
 * 扩展声明为成员
 *
 * 在一个类内部你可以为另一个类声明扩展。在这样的扩展内部，
 * 有多个 隐式接收者 —— 其中 的对象成员可以无需通过限定符访问。扩展声明所在的类的实例称为 分发接收者，
 * 扩展方法 调用所在的接收者类型的实例称为 扩展接收者 。
 *
* */
class F {
    fun bar() {
        println("F.bar()")
    }
}
class G {
    fun baz() {
        println("G.baz()")
    }
    fun F.foo() {
        bar() // 调用 F.bar baz() // 调用 C.baz
    }
    fun caller(d: D) {
        d.foo() // 调用扩展函数
    }
}